home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 November: Tool Chest / Dev.CD Nov 96 TC / Dev.CD Nov 96 TC.toast / Sample Code / Interapplication Communication / MenuScripter 4.0 / Sources / MSGXPrinting.c < prev    next >
Encoding:
Text File  |  1996-07-09  |  15.9 KB  |  561 lines  |  [TEXT/CWIE]

  1. // MSGXPrinting.c
  2. //
  3. // Original version by Jon Lansdell and Nigel Humphreys.
  4. // 4.0 and 3.1 updates by Greg Sutton.
  5. // GX printing by Don Swatman
  6. // ©Apple Computer Inc 1996, all rights reserved.
  7.  
  8. // Adds GX printing functionality to MenuScripter
  9.  
  10. /*    
  11.     Changes for 4.0
  12.  
  13.     29-Feb-96 : GS : Changed <Graphics routines.h> to <GXGraphics.h>
  14.                                         Changed <graphics toolbox.h> to <GXEnvironment.h>
  15. */
  16.  
  17. #include <Gestalt.h>
  18.  
  19. #ifdef __MWERKS__
  20.     #include <Graphics routines.h>
  21.     #include <graphics toolbox.h>
  22. #else
  23.     #include <GXGraphics.h>
  24.     #include <GXPrinting.h>
  25. #endif
  26.  
  27. #include <GXEnvironment.h>
  28. #include "QDLibrary.h"
  29.  
  30.  
  31. #include "MSGXPrinting.h"
  32. #include "MSWindow.h"
  33. #include "MSGlobals.h"
  34. #include "MSMain.h"
  35. #include "MSAEWindowUtils.h"
  36.  
  37. // Constants
  38.  
  39. #define        kGraphicsHeapSize    ((long) 300 * 1024)
  40.  
  41. // Globals
  42. gxGraphicsClient gClient;
  43.  
  44.  
  45. //-------------------------------------------------------
  46. //       InitGXIfPresent
  47. //
  48. // This uses Gestalt() to see if QuickDraw GX is present.
  49. // If it is, it then initialises the GX managers.
  50. // If it isn't, then it removes the GX file menu item(s).
  51. //-------------------------------------------------------
  52.  
  53. #pragma segment Main
  54.  
  55. void InitGXIfPresent(void)
  56. {
  57.     long gxVersion;
  58.     long gxPrintVersion;
  59.  
  60.     gGXIsPresent = false;
  61.  
  62. // Check to see whether QuickDraw GX is available.
  63.     if (Gestalt(gestaltGXVersion, &gxVersion) == noErr)
  64.         if (Gestalt(gestaltGXPrintingMgrVersion, &gxPrintVersion) == noErr)
  65.             gGXIsPresent = true;
  66.  
  67.     if (gGXIsPresent)
  68.     {
  69. // Initialize QuickDraw GX.
  70.         gClient = GXNewGraphicsClient(nil, kGraphicsHeapSize, (gxClientAttribute) 0);
  71.         GXEnterGraphics();
  72.         GXInitPrinting();
  73.     }
  74.     else
  75.     {
  76. // No QuickDraw GX, so remove extra file menu item(s)
  77.         DelMenuItem ( myMenus[fileM], fmPrintOne);
  78.     }
  79. }
  80.  
  81. //-------------------------------------------------------
  82. //       CleanUpGXIfPresent
  83. //
  84. // If GX was installed (i.e. gGXIsPresent) then remove
  85. // the GX managers.
  86. //-------------------------------------------------------
  87.  
  88. #pragma segment Main
  89.  
  90. void CleanUpGXIfPresent(void)
  91. {
  92.     if (gGXIsPresent)
  93.     {
  94.         GXExitPrinting();
  95.         GXDisposeGraphicsClient(gClient);
  96.         GXExitGraphics();
  97.     }
  98. }
  99.  
  100. //-------------------------------------------------------
  101. //       ConvertMenuActualToGXMenu
  102. //
  103. // This converts an item number as returned by MenuKey()
  104. // or MenuSelect() to the value used internally. The reason
  105. // you have to this is because a non gx application has
  106. // less items in the file menu.
  107. //-------------------------------------------------------
  108.  
  109. #pragma segment Main
  110.  
  111. short ConvertMenuActualToGXMenu ( short theItem )
  112. {
  113.     short menuItem;
  114.     
  115.     menuItem = theItem;    
  116.     if (!gGXIsPresent)
  117.     {
  118.         if (theItem == fmNoGXPrint)
  119.             menuItem = fmPrint;
  120.         else
  121.             if (theItem == fmNoGXQuit)
  122.                 menuItem = fmQuit;
  123.     }
  124.     return menuItem;
  125. }
  126.  
  127. //-------------------------------------------------------
  128. //       GetRectOfPage
  129. //
  130. // This returns a QuickDraw rect for the current printer page.
  131. // If gx is not present if uses rPage from the document's THPrint.
  132. // If gx is present then we get a GXRectangle from the requested
  133. // page's format. It then converts this to a Rect. This could be
  134. // extended to handle custom formated pages.
  135. //-------------------------------------------------------
  136.  
  137. #pragma segment Main
  138.  
  139. void GetRectOfPage( DPtr  theDoc,
  140.                                         Rect  *pageRect )
  141. {
  142.     gxFormat        pageFormat;
  143.     gxRectangle pageSize;
  144.     gxRectangle paperSize;
  145.  
  146.     if (gGXIsPresent)
  147.     {
  148.             pageFormat = GXGetJobFormat(theDoc->documentJob, 1);
  149.             GXGetFormatDimensions(pageFormat, &pageSize, &paperSize);
  150.     // Convert to a QD Rect
  151.             FixedRectToShort( &pageSize, pageRect );
  152.     }
  153.     else
  154.         *pageRect = (*(theDoc->thePrintSetup))->prInfo.rPage;
  155.     OffsetRect( pageRect, -pageRect->left, -pageRect->top);
  156. }
  157.  
  158. //-------------------------------------------------------
  159. //       AdjustMenusForGXPrintDialogs
  160. //
  161. // This enables or disables menu's when the GX print dialog
  162. // is being displayed.
  163. //-------------------------------------------------------
  164.  
  165. #pragma segment GXPrintSeg
  166.  
  167. void AdjustMenusForGXPrintDialogs( Boolean dialogGoingUp )
  168. {
  169.     Boolean redrawMenuBar = false;
  170.     
  171.     if (dialogGoingUp)
  172.     {
  173.         SetMenuItemState ( false, myMenus[appleM], aboutItem);
  174.         redrawMenuBar |= SetMenuItemState ( false, myMenus[fileM], kMenuTitle );
  175.         if ( CountDocuments( ) )
  176.         {
  177.             redrawMenuBar |= SetMenuItemState ( false, myMenus[fontM],  kMenuTitle);
  178.             redrawMenuBar |= SetMenuItemState ( false, myMenus[sizeM],  kMenuTitle);
  179.             redrawMenuBar |= SetMenuItemState ( false, myMenus[styleM], kMenuTitle);
  180.  
  181.                redrawMenuBar |= SetMenuItemState ( false, myMenus[scriptM],     kMenuTitle);
  182.             redrawMenuBar |= SetMenuItemState ( false, myMenus[subroutineM], kMenuTitle);
  183.  
  184.             SetMenuItemState ( false, myMenus[editM], selectAllCommand);
  185.         }
  186.         HiliteMenu(0);
  187.  
  188.     }
  189.     else
  190.     {
  191.                 SetMenuItemState ( true, myMenus[appleM], aboutItem);
  192.                 redrawMenuBar |= SetMenuItemState ( true, myMenus[fileM], kMenuTitle);
  193.                 redrawMenuBar |= SetMenuItemState ( true, myMenus[editM], kMenuTitle);
  194.                 if ( CountDocuments( ) )
  195.                 {
  196.                   redrawMenuBar |= SetMenuItemState ( true, myMenus[fontM],  kMenuTitle);
  197.                   redrawMenuBar |= SetMenuItemState ( true, myMenus[sizeM],  kMenuTitle);
  198.                   redrawMenuBar |= SetMenuItemState ( true, myMenus[styleM], kMenuTitle);
  199.             
  200.                redrawMenuBar |= SetMenuItemState ( true, myMenus[scriptM],     kMenuTitle);
  201.             redrawMenuBar |= SetMenuItemState ( true, myMenus[subroutineM], kMenuTitle);
  202.  
  203.                   SetMenuItemState ( true, myMenus[editM], selectAllCommand);
  204.                 }
  205.                 MaintainMenus( &redrawMenuBar );
  206.     }
  207.  
  208.       if (redrawMenuBar)
  209.             DrawMenuBar();
  210. }
  211.  
  212. //-------------------------------------------------------
  213. //       SetupGXEditMenuRec
  214. //
  215. // Sets up the gxEditMenuRecord. This is used by the
  216. // GX dialogs so that they know where the items in the
  217. // Edit Menu are
  218. //-------------------------------------------------------
  219.  
  220. #pragma segment GXPrintSeg
  221.  
  222. void SetupGXEditMenuRec(gxEditMenuRecord *editMenuRec)
  223.     {
  224.         editMenuRec->editMenuID = editID;
  225.         editMenuRec->cutItem    =   cutCommand;
  226.         editMenuRec->copyItem   =   copyCommand;
  227.         editMenuRec->pasteItem  =   pasteCommand;
  228.         editMenuRec->clearItem  =   clearCommand;
  229.         editMenuRec->undoItem   =   undoCommand;
  230.     }
  231.  
  232. //-------------------------------------------------------
  233. //       DoGXPageSetup
  234. //
  235. //  Puts up a GX Page Setup dialog
  236. //-------------------------------------------------------
  237.  
  238. #pragma segment GXPrintSeg
  239.  
  240. Boolean DoGXPageSetup ( DPtr theDoc )
  241.     {
  242.         Boolean          result = false;
  243.             OSErr            theErr;
  244.             gxDialogResult   dialogResult;
  245.             gxEditMenuRecord editMenuRec;
  246.             
  247.             if (gGXIsPresent)
  248.                 if (theDoc)
  249.                 {
  250.                     AdjustMenusForGXPrintDialogs(true);
  251.                     SetupGXEditMenuRec( &editMenuRec );
  252.  
  253. // Display the Page Setup dialog box.
  254.                     dialogResult = GXJobDefaultFormatDialog ( theDoc->documentJob, &editMenuRec);
  255.                     theErr = GXGetJobError(theDoc->documentJob);
  256.  
  257.                     AdjustMenusForGXPrintDialogs(false);
  258.  
  259. // Return True, if there are no Errors and the OK button was clicked
  260.                     result = ((theErr == noErr) && (dialogResult == gxOKSelected));
  261.                 }
  262.         return(result);
  263.     }
  264.  
  265.  
  266. //-------------------------------------------------------
  267. //       struct GXPrintSpoolDataRec
  268. //
  269. //  Used to pass information during printing
  270. //-------------------------------------------------------
  271.  
  272. typedef struct GXPrintSpoolDataRec
  273. {
  274.     gxRectangle   pageArea;                // Page rectangle.
  275.     gxViewPort    printViewPort;  // View port we're printing in.
  276. } GXPrintSpoolDataRec, *GXPrintSpoolDataPtr;
  277.  
  278. //-------------------------------------------------------
  279. //       PrintAShape
  280. //
  281. //  Called after shape translation. It checks to see if any shape
  282. // it recieves are drawable, the draws it in the GX view port.
  283. // Information in the form of a pointer to a GXPrintSpoolDataRec
  284. // is passed in the refCon.
  285. //-------------------------------------------------------
  286.  
  287. #pragma segment GXPrintSeg
  288.  
  289. OSErr PrintAShape(gxShape currentShape, long refCon)
  290. {
  291.     GXPrintSpoolDataPtr spoolData;
  292.     gxShapeType         theShapeType;
  293.  
  294. // Get the spool data from the refCon
  295.     spoolData = (GXPrintSpoolDataPtr) refCon;
  296.  
  297. // Don't waste time spooling the shape if it's being drawn off the page.
  298.  
  299.     theShapeType = GXGetShapeType(currentShape);
  300.     if (   (theShapeType == gxEmptyType)
  301.             || (theShapeType == gxFullType)
  302.             || (theShapeType == gxPictureType)
  303.             || GXTouchesBoundsShape(&spoolData->pageArea, currentShape) )
  304.     {
  305.  
  306. // Set the ports and draw it
  307.         GXSetShapeViewPorts(currentShape, 1, &spoolData->printViewPort);
  308.         GXDrawShape(currentShape);
  309.     }
  310.     return (OSErr) GXGetGraphicsError(nil);
  311. }
  312.  
  313. //-------------------------------------------------------
  314. //       DuplicateStyleTERec
  315. //
  316. // This copies the styled TERec in theDoc. It puts it into
  317. // the destPort
  318. //-------------------------------------------------------
  319.  
  320. #pragma segment Main
  321.  
  322. void DuplicateStyleTERec( TEHandle  hSourceTE,
  323.                                                     TEHandle *hDestTE,
  324.                                                     Rect     *destRect,
  325.                                                     GrafPtr   destPort )
  326. {
  327.     GrafPtr oldPort;
  328.     short   oldSelStart;
  329.     short   oldSelEnd;
  330.     StScrpHandle printerTextStyles;
  331.     
  332. // Set up the ports
  333.     GetPort(&oldPort);
  334.     SetPort(destPort);
  335.     
  336. // Create a temporary Text Edit and copy the windows text edit into it
  337.     *hDestTE = TEStyleNew(destRect, destRect);
  338.  
  339. // Select all the text (preserving the previous settings) so that we can use 
  340. // GetTylScrap (or TEGetStyleScrapHandle ) to get the style of the whole TERec
  341.     oldSelStart = (*hSourceTE)->selStart;
  342.     oldSelEnd   = (*hSourceTE)->selEnd;
  343.     TESetSelect(0,(*hSourceTE)->teLength, hSourceTE);
  344.  
  345. // Get the style
  346.     printerTextStyles = GetStylScrap(hSourceTE);
  347.  
  348. // Revert the selection range
  349.     TESetSelect(oldSelStart, oldSelEnd, hSourceTE);
  350.  
  351. // Move the text from the documents TERec and add the style (got above) to it
  352.     HLock((Handle)((*hSourceTE)->hText));
  353.     TEStyleInsert ( (Ptr)*((*hSourceTE)->hText),
  354.                                     (*hSourceTE)->teLength,
  355.                                     printerTextStyles,
  356.                                     *hDestTE);        
  357.     HUnlock((Handle)((*hSourceTE)->hText));
  358.  
  359. // Deactivat the temporary TERec
  360.     TEDeactivate(*hDestTE);
  361.     
  362. // Reset the port
  363.     SetPort(oldPort);
  364. }
  365.  
  366. //-------------------------------------------------------
  367. //       GXPrintLoop
  368. //
  369. // This does the actual printing. It creates a invisible window
  370. // to draw into. It duplicates the Text Edit record in the 
  371. // document to a temporary record. It puts up the progress
  372. // dialog then it steps through the pages. At each page, it
  373. // clips the text edit rec so it doesn't draw lines of text
  374. // over two pages. It then uses TEUpdate to draw each page and
  375. // finally scroll's the text edit rec ready for the next page.
  376. //-------------------------------------------------------
  377.  
  378.  
  379. #pragma segment GXPrintSeg
  380.  
  381. OSErr GXPrintLoop ( DPtr theDoc)
  382. {
  383.     OSErr      theErr = noErr;
  384.      WindowPtr  imagingWind;              // Temp window we're going to draw into
  385.     gxViewPort printViewPort;            // Printer view port
  386.     Rect       tempWindRect = {0,0,0,0}; // Bounds for temp window
  387.   TEHandle   tempTE;                   // Copy of the documents text edit record
  388.      PageEndsArray pageEnds;           
  389.     short      numDocPages;
  390.     long       firstPage;
  391.     long       lastPage;
  392.     long       numPagesToPrint;
  393.     long       pageCounter;
  394.     Point      patStretch = {1,1};
  395.     gxFormat   pageFormat;
  396.     Rect       everywhereRect;
  397.     Str255     windTitle;
  398.     GXPrintSpoolDataRec spoolData;
  399.     Rect       printerPage;
  400.     Rect       rectToClip;
  401.  
  402. // Create a window to draw into. It's bounds are small(0,0,0,0)
  403. // and it's not shown so it doesn't appear to the user 
  404.     imagingWind = NewWindow ( nil, &tempWindRect, "\p",
  405.                                                         false, documentProc, (WindowPtr)-1,
  406.                                                         false, 0);
  407.  
  408. // Set the port to the imaging port
  409.     SetPort((GrafPtr)imagingWind);
  410.     
  411. // Get the size of the printers page 
  412.     GetRectOfPage ( theDoc, &printerPage );
  413.  
  414. // Duplicate the text edit record from the document
  415.     DuplicateStyleTERec( theDoc->theText, &tempTE, &printerPage, (GrafPtr)imagingWind );
  416.  
  417.  
  418. // Work out the size of each page using GetPageEnds. This stops text
  419. //  drawing over two pages
  420.  
  421.     (*tempTE)->destRect = printerPage;
  422.     GetPageEnds(printerPage.bottom-printerPage.top,
  423.                             tempTE,
  424.                             pageEnds,
  425.                             &numDocPages);
  426.     
  427.  
  428. // Determine which pages the user selected to print, and print
  429. // only those pages that are actually in the document. 
  430.     GXGetJobPageRange(theDoc->documentJob, &firstPage, &lastPage);
  431.     if (lastPage > numDocPages)
  432.         lastPage = numDocPages;
  433.  
  434. // Calculate the number of pages to print and begin printing. 
  435.     numPagesToPrint = lastPage - firstPage + 1;
  436.     theErr = GXGetJobError(theDoc->documentJob);
  437.     if (!theErr)
  438.     {
  439. // Get the title of the window as we'll use this for the name we call the print job
  440.         GetWTitle ( theDoc->theWindow, windTitle);
  441.  
  442. // Put up the print progress dialog
  443.         GXStartJob( theDoc->documentJob,
  444.                                 windTitle, 
  445.                                 numPagesToPrint);
  446.         theErr = GXGetJobError(theDoc->documentJob);
  447.         if (!theErr)
  448.         {
  449. // Create a new view port for printing and set our translator
  450. //    rects to "wide open" so that they include all data we're
  451. //    drawing. For each page we print, call GXStartPage, draw,
  452. //    and call GXFinishPage. 
  453.             SetRect(&everywhereRect, 0, 0, 32767, 32767);
  454.             printViewPort = GXNewViewPort(gxScreenViewDevices);
  455.         
  456.             for (pageCounter = firstPage; (theErr == noErr) && (pageCounter <= lastPage); pageCounter++)
  457.             {
  458. // Get the page's format and start printing the page.
  459.                 pageFormat = GXGetJobFormat(theDoc->documentJob, 1);
  460.         
  461.                 GXStartPage(theDoc->documentJob, pageCounter, pageFormat, 1, &printViewPort);                                
  462.                 theErr = GXGetJobError(theDoc->documentJob);
  463.         
  464. // If there were no errors, set up the translator, draw
  465. // the QuickDraw data for current page, and remove the
  466. // translator.
  467.                 if (!theErr)
  468.                 {
  469.     // Set up spool data
  470.                     spoolData.printViewPort = printViewPort;
  471.                     GXGetFormatDimensions( pageFormat, &spoolData.pageArea, nil);
  472.  
  473.   // Install the translator
  474.                     GXInstallQDTranslator((GrafPtr)imagingWind,
  475.                                                                 gxDefaultOptionsTranslation,
  476.                                                                 &everywhereRect,
  477.                                                                 &everywhereRect,
  478.                                                                 patStretch,
  479.                                                                 NewgxShapeSpoolProc ( PrintAShape ),
  480.                                                                 &spoolData);
  481.  
  482. // Make sure it draws into the correct QuickDraw window
  483.                     SetPort((GrafPtr)imagingWind);
  484.  
  485. // Clip the page to the size of the current page
  486.                     rectToClip = printerPage;
  487.                     if (pageCounter == 1)
  488.                         rectToClip.bottom = rectToClip.top + pageEnds[pageCounter-1];
  489.                     else
  490.                         rectToClip.bottom = rectToClip.top
  491.                                                                 + ( pageEnds[pageCounter-1] - pageEnds[pageCounter-2] );
  492.                     ClipRect(&rectToClip);
  493.  
  494. // Use TEUpdate to do the drawing
  495.                     TEUpdate(&printerPage, tempTE);
  496.  
  497. // Remove the Translator
  498.                     GXRemoveQDTranslator((GrafPtr)imagingWind, nil);
  499.  
  500. // Finish off this page
  501.                     GXFinishPage(theDoc->documentJob);
  502.  
  503. // Scroll the text edit down to the next page
  504.                     if (pageCounter < lastPage)
  505.                         TEScroll(0,rectToClip.top-rectToClip.bottom, tempTE);
  506.                 }
  507.             }
  508. // All done, so finish the printer job and dispose of the GXView port
  509.             GXFinishJob(theDoc->documentJob);
  510.             theErr = GXGetJobError(theDoc->documentJob);
  511.             GXDisposeViewPort(printViewPort);
  512.         }
  513.     }
  514.  
  515. // Dispose of temporary TERec and imaging window
  516.     TEDispose ( tempTE );
  517.     DisposeWindow ( imagingWind );
  518.  
  519.     return theErr;
  520. }
  521.     
  522. //-------------------------------------------------------
  523. //       GXPrintDocument
  524. //
  525. // This puts up the print dialog box, then calls GXPrintLoop()
  526. // to do the actual printing.
  527. //-------------------------------------------------------
  528.  
  529. #pragma segment GXPrintSeg
  530.  
  531. OSErr GXPrintDocument ( DPtr    theDoc,
  532.                                                 Boolean askUser )
  533. {
  534.     OSErr                        err = noErr;
  535.     gxEditMenuRecord    editMenuRec;
  536.     gxDialogResult        dialogResult;
  537.  
  538. // Put up the print dialog if askUser is set to true
  539.     if (!askUser)
  540.         dialogResult = gxOKSelected;
  541.     else
  542.     {
  543. // Set up the edit menu record so GX knows how to gray it
  544.         SetupGXEditMenuRec( &editMenuRec );
  545.     
  546.         AdjustMenusForGXPrintDialogs(true);
  547.         dialogResult = GXJobPrintDialog(theDoc->documentJob, 
  548.                                                             &editMenuRec);
  549.         AdjustMenusForGXPrintDialogs(false);
  550.     }
  551.  
  552. // if ok selected, then print the pages
  553.     if (dialogResult == gxOKSelected)
  554.         err = GXPrintLoop(theDoc);
  555.     else
  556.         err = userCanceledErr;
  557.  
  558.     return err;
  559. }
  560.  
  561.